﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using GGSharp.Http;
using System.Net;
using System.IO;
using GGSharp.Radio;
using System.Security.Cryptography.X509Certificates;
using GGSharp.Radio.XML;

namespace GGSharp
{
    public class GGRadio
    {
        public delegate void ResponseReceivedDelegate(object sender, RDSResponseBase response);

        public event ResponseReceivedDelegate ResponseReceived;

        protected const string USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 (.NET CLR 3.5.30729)";
        protected const string DEFAULT_CHANNELS_VERSION = "2009010801";

        private bool _autoUpdateChannels = true;
        private ChannelList _channelList;

        private string _version = "7.7.0.3725";
        private string _versionHash = "ea509f39d8b45bac63326036c14540d2";

        protected void Authenticate(LoginResponse response)
        {
            RequestInfo request = response.Request;
            request.Url = String.Format("{0}?u={1}&h={2}&v={3}", response.AuthorizationServer, request.Number, _versionHash, _version);
            ReceiveResponse(request);
        }

        public void Login(int number, string password, Channel channel)
        {
            ChannelServer server = channel.Servers[0];
            Login(number, password, server.Address, channel.Name);
        }

        public void Login(int number, string password, string server, int channel)
        {
            string channelsVersion = _channelList != null ? Channels.Version : DEFAULT_CHANNELS_VERSION;
            Login(number, password, server, channel, channelsVersion);
        }

        public void Login(int number, string password, string server, int channel, string channelsVersion)
        {
            RequestInfo request = new RequestInfo();
            request.Channel = channel;
            request.Number = number;
            request.Password = password;
            request.Url = String.Format("https://{0}/auth.gg?u={1}&p={2}&c={3}&v={4}&s={5}&w=5.2.4.703&r=0", server, number, password, channel, _version, channelsVersion);
            ReceiveResponse(request);
        }

        protected void Login(RepeatLoginResponse repeatResponse)
        {
            RequestInfo request = repeatResponse.Request;
            Login(request.Number, request.Password, repeatResponse.LoginServer, request.Channel);
        }

        protected void ReceiveResponse(RequestInfo request)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveResponse_WaitCallback), request);
        }

        bool sth(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors errors)
        {
            return true;
        }

        protected void ReceiveResponse_WaitCallback(object data)
        {
            RequestInfo requestInfo = (RequestInfo)data;

            try
            {
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(sth);

                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestInfo.Url);
                request.Method = "GET";
                request.UserAgent = USER_AGENT;
                request.ContentLength = 0;

                StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream(), Encoding.UTF8);
                string response = reader.ReadToEnd();
                reader.Close();
                ParseResponse(response, requestInfo);


            }
            catch (Exception e)
            {
                ParseResponse("0;1;" + e.Message + ";", requestInfo);
            }
        }

        protected void ParseResponse(string response, RequestInfo request)
        {
            RDSResponseBase responseBase = null;
            switch (response[0])
            {
                case '0':
                    responseBase = new ErrorResponse(request);
                    responseBase.Read(response);
                    break;
                case '1':

                    if (response[2] == '1')
                    {
                        responseBase = new LoginResponse(request);
                        responseBase.Read(response);

                        LoginResponse loginResponse = (LoginResponse)responseBase;
                        Authenticate(loginResponse);

                        //update channels
                        if (_autoUpdateChannels && loginResponse.ChannelListAddress != null)
                            Channels.BeginRead(loginResponse.ChannelListAddress, null, null);
                    }
                    else
                    {
                        responseBase = new StreamResponse(request);
                        responseBase.Read(response);

                    }
                    break;
                case '2':
                    responseBase = new RepeatLoginResponse(request);
                    responseBase.Read(response);
                    Login(responseBase as RepeatLoginResponse);
                    break;
            }

            OnResponseReceived(responseBase);
        }

        protected virtual void OnResponseReceived(RDSResponseBase response)
        {
            if (ResponseReceived != null)
                ResponseReceived(this, response);
        }

        public bool AutoUpdateChannels
        {
            get { return _autoUpdateChannels; }
            set { _autoUpdateChannels = value; }
        }

        public void SetVersion(string version, string versionHash)
        {
            _version = version;
            _versionHash = versionHash;
        }

        public ChannelList Channels
        {
            get
            {
                if (_channelList == null)
                    _channelList = new ChannelList();

                return _channelList;
            }
        }
    }
}
